package com.jungle.bfi.metadata.swagger;


import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;

import java.lang.reflect.InvocationTargetException;
import java.util.EnumMap;
import java.util.Map;
import java.util.function.Function;


public class OperationSelector {

    private Operation operation;
    private PathItem.HttpMethod method;

    public OperationSelector(PathItem pathItem) {
        init(pathItem);
    }

    private void init0(PathItem pathItem) {
        if (pathItem != null) {
            for (PathItem.HttpMethod httpMethod : PathItem.HttpMethod.values()) {
                try {
                    String lowerCase = httpMethod.name().toLowerCase();
                    char chr = lowerCase.charAt(0);
                    if (chr >= 'a' && chr <= 'z') {
                        lowerCase = Character.toUpperCase(chr) + lowerCase.substring(1);
                    }
                    Object invoke = PathItem.class.getMethod("get"+ lowerCase).invoke(pathItem);
                    if (invoke != null) {
                        operation = (Operation) invoke;
                        method = httpMethod;
                        return;
                    }
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ignored) {
                    // ignore
                }
            }
        }
    }

    private void init(PathItem pathItem) {
        if (pathItem != null) {
            Map<PathItem.HttpMethod, Function<PathItem, Operation>> map = new EnumMap<>(PathItem.HttpMethod.class);
            map.put(PathItem.HttpMethod.GET, PathItem::getGet);
            map.put(PathItem.HttpMethod.POST, PathItem::getPost);
            map.put(PathItem.HttpMethod.PUT, PathItem::getPut);
            map.put(PathItem.HttpMethod.DELETE, PathItem::getDelete);
            map.put(PathItem.HttpMethod.PATCH, PathItem::getPatch);
            map.put(PathItem.HttpMethod.OPTIONS, PathItem::getOptions);
            map.put(PathItem.HttpMethod.HEAD, PathItem::getHead);
            map.put(PathItem.HttpMethod.TRACE, PathItem::getTrace);

            for (Map.Entry<PathItem.HttpMethod, Function<PathItem, Operation>> entry : map.entrySet()) {
                if (entry.getValue().apply(pathItem) != null) {
                    operation = entry.getValue().apply(pathItem);
                    method = entry.getKey();
                    break;
                }
            }
        }
    }

    public Operation getOperation() {
        return operation;
    }

    public PathItem.HttpMethod getMethod() {
        return method;
    }
}
